#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2025, Lime Technology
 * Copyright 2012-2025, Bergware International.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2,
 * as published by the Free Software Foundation.
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 */
?>
<?
$docroot = '/usr/local/emhttp';
$net     = '/sys/class/net';
$bond    = '/proc/net/bonding';
$md5_old = -1;
$data    = [];

require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/publish.php";
extract(parse_plugin_cfg('dynamix',true));

// add translations
$_SERVER['REQUEST_URI'] = 'dashboard/main';
$login_locale = _var($display,'locale');
require_once "$docroot/webGui/include/Translations.php";

// remember current language
$locale_init = $locale;

function update_translation($locale) {
  global $docroot,$language;
  $language = [];
  if ($locale) {
    $text = "$docroot/languages/$locale/translations.txt";
    if (file_exists($text)) {
      $store = "$docroot/languages/$locale/translations.dot";
      if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
      $language = unserialize(file_get_contents($store));
    }
    $text = "$docroot/languages/$locale/dashboard.txt";
    if (file_exists($text)) {
      $store = "$docroot/languages/$locale/dashboard.dot";
      if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
      $language = array_merge($language,unserialize(file_get_contents($store)));
    }
  }
}
function ports() {
  global $net;
  exec("ls --indicator-style=none $net|grep -Po '^(bond|eth|wlan)\d+$'",$ports);
  $ports[] = 'lo';
  return $ports;
}

function port_get_contents($port) {
  return file_exists($port) ? @file_get_contents($port) : 0;
}

function esc($text) {
  // escape literal text in date format string
  return "\\".join("\\",str_split($text));
}

// initialize variables
$time0 = $time1 = microtime(true);
foreach (ports() as $port) {
  $data[$port]['rx'] = (float)port_get_contents("$net/$port/statistics/rx_bytes");
  $data[$port]['tx'] = (float)port_get_contents("$net/$port/statistics/tx_bytes");
}
// loop
while (true) {
  // check for language changes
  extract(parse_plugin_cfg('dynamix',true));
  if (_var($display,'locale') != $locale_init) {
    $locale_init = _var($display,'locale');
    update_translation($locale_init);
  }
  $echo = [];
  $echo['port'] = $echo['mode'] = $echo['rxtx'] = $echo['stat'] = [];
  $ts = $time1 - $time0;
  foreach (ports() as $port) {
    // inbound + outbound speed
    $rx = (float)port_get_contents("$net/$port/statistics/rx_bytes");
    $tx = (float)port_get_contents("$net/$port/statistics/tx_bytes");
    if ($ts > 0) {
      $rxd = ($rx-_var($data[$port],'rx',0))/$ts*8;
      $txd = ($tx-_var($data[$port],'tx',0))/$ts*8;
      $rx_speed = my_scale($rxd,$unit,1,-1).' '.str_replace('B','b',$unit).'ps';
      $tx_speed = my_scale($txd,$unit,1,-1).' '.str_replace('B','b',$unit).'ps';
    } else {
      $rxd = $txd = 0;
      $rx_speed = '---';
      $tx_speed = '---';
    }
    $data[$port]['rx'] = $rx;
    $data[$port]['tx'] = $tx;
    $echo['port'][] = [$port,$rx_speed,$tx_speed,$rxd,$txd];
    // interface general information
    $mtu = port_get_contents("$net/$port/mtu");
    $link = port_get_contents("$net/$port/carrier")==1;
    switch (substr($port,0,4)) {
    case 'bond':
      if ($link) {
        $bond_mode = file_exists("$bond/$port") ? str_replace('Bonding Mode: ','',@file("$bond/$port",FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)[1]) : '---';
        $echo['mode'][] = "$bond_mode, mtu $mtu";
      } else {
        $echo['mode'][] = "bond down";
      }
      break;
    case 'wlan':
      if ($link) {
        unset($speed);
        exec("iw $port link | awk '/^\s+[rt]x bitrate: /{print $1,$2,$3,$4}'",$speed);
        if (count($speed)==2) {
          [$rxrate, $rxunit] = explode(' ',explode(': ',$speed[0])[1]);
          [$txrate, $txunit] = explode(' ',explode(': ',$speed[1])[1]);
          $echo['mode'][] = _('Rx').": ".round($rxrate)." ".str_replace('Bit/s','bps',$rxunit).", "._('Tx').": ".round($txrate)." ".str_replace('Bit/s','bps',$txunit).", mtu $mtu";
        } else {
          $echo['mode'][] = _('not connected');
        }
      } else {
        $echo['mode'][] = _('interface down');
      }
      break;
    case 'lo':
      $echo['mode'][] = $link ? _('loopback') : _('not set');
      break;
    default:
      if ($link) {
        $speed = port_get_contents("$net/$port/speed");
        $duplex = port_get_contents("$net/$port/duplex");
        $echo['mode'][] = "$speed Mbps, $duplex duplex, mtu $mtu";
      } else {
        $echo['mode'][] = _('interface down');
      }
      break;
    }
    // interface counters
    $echo['rxtx'][] = $rx;
    $echo['rxtx'][] = $tx;
    // interface errors
    $rx_errors = port_get_contents("$net/$port/statistics/rx_errors");
    $rx_drops  = port_get_contents("$net/$port/statistics/rx_dropped");
    $rx_fifo   = port_get_contents("$net/$port/statistics/rx_fifo_errors");
    $tx_errors = port_get_contents("$net/$port/statistics/tx_errors");
    $tx_drops  = port_get_contents("$net/$port/statistics/tx_dropped");
    $tx_fifo   = port_get_contents("$net/$port/statistics/tx_fifo_errors");
    $echo['stat'][] = "Errors: {$rx_errors}<br>Drops: {$rx_drops}<br>Overruns: {$rx_fifo}";
    $echo['stat'][] = "Errors: {$tx_errors}<br>Drops: {$tx_drops}<br>Overruns: {$tx_fifo}";
  }
  // current date and time
  $now   = time();
  $xtime = _var($display,'time')!='%R';
  $xdate = _var($display,'date')=='%c';
  $clock = date($xtime||$xdate ? 'g:i '.esc('<span class="ampm">').'a'.esc('</span>') : 'G:i',$now);
  $date  = my_date($xdate ? 'D j M Y, T' : $display['date'].', T',$now);
  $echo['time'] = [$clock,_($date,0)];

  $echo = json_encode($echo);
  $md5_new = md5($echo,true);
  if ($md5_new !== $md5_old) {
    $md5_old = publish('update3',$echo)!==false ? $md5_new : -1;
    $time0 = $time1;
  }
  sleep(1);
  $time1 = microtime(true);
}
